/**
* @brief
*		Find errors and decrease probability of getting errors of the same kind in the future
*		This piece of code won't compile and it doesn't describe an entire algorithm: just part of some page storage
*
* @author
*		AnnaM
*/

#include <Windows.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>

enum PAGE_COLOR 
{
	PG_COLOR_GREEN = 0, /* page may be released without high overhead */
	PG_COLOR_YELLOW, /* nice to have */
	PG_COLOR_RED,	/* page is actively used */
	PG_COLOR_SIZE /* size of array to store colors */
}
// FIXED: COLORS begin from 0 and we have PG_COLOR_SIZE for PgStrg array. 

/**
 * UINT Key of a page in hash-table (prepared from color and address)
 */

// FIXED: let's use uint32_t which size is always 32 bits
union PageKey
{
	struct
	{
		char cColor: 8;
		uint32_t cAddr: 24; 
	};

	uint32_t uKey;
};

// FIXED: brakets and do while
/* Prepare from 2 chars the key of the same configuration as in PageKey */
#define CALC_PAGE_KEY( Addr, Color ) do { ((Color) + ((Addr) << 8)) } while (0)
// А вообще лучше inlene-функцию:
inline PageKey CalcPageKey(uint32_t addr, PAGE_COLOR color) {
	return addr << 8 + color; // А надо ли проверять переполнение Addr? От смысла зависит	
}


/**
 * Descriptor of a single guest physical page
 */
struct PageDesc
{
	PageKey			uKey;

	/* list support */
	PageDesc		*next, *prev;
};uint32_t addr, 

// FIXED: do while
#define PAGE_INIT(uKey = c, Addr, Color )           \
    do  {                                           \
        (Desc).uKey = CALC_PAGE_KEY( Addr, Color ); \
        (Desc).next = (Desc).prev = NULL;           \
    } while (0)

// Но лучше и здесь inline-функцию
inline void PageInit(PageDesk *pdesk, uint32_t addr, PAGE_COLOR color) 
{
	assert(pdesk);
	pdesk->uKey = CalcPageKey(addr, color);
	pdesk->next = pdesk->prev = NULL;
}

// FIXED: array size
// А заслуживает ли он быть глобальным?! 
static PageDesc* PageStrg[ PG_COLOR_SIZE ];
// А вообще, хорошо бы сделать хотя бы структуру с флагом на состояние инициализации!

void PageStrgInit()
{
	// FIXED: sizeof size
	memset( PageStrg, 0, sizeof(PageDesc) * PG_COLOR_SIZE );
}
// FIXED: all pointers checked and types changed
PageDesc* PageFind( uint32_t ptr, PAGE_COLOR color )
{
	// FIXED: Нехорошо дальше юзать переменные изнутри for. Тольков VS прокатит
	PageDesc *Pg = PageStrg[color];
	if (!Pg)
		return NULL;
	// FIXED: always NULL fixed
	for (; Pg->next; Pg = Pg->next );
        if( Pg->uKey == CALC_PAGE_KEY(ptr,color) )
		return Pg;
	return NULL;
}

PageDesc* PageReclaim( uint32_t cnt )
{
	PAGE_COLOR color = 0; // FIXED: color type
	PageDesc* Pg = PageStrg[0]; // FIXME: У меня недостаточно данных, чтобы это исправить, но я попробовал
	while( cnt )
	{
		// Я не понимаю, что здесь должно происходить: могу понаставить проверок,ноне понять смысл
		Pg = Pg->next;
		PageRemove( PageStrg[ color ] );
		cnt--;
		if( Pg == NULL )
		{
			color++; // FIXME  ??
			Pg = PageStrg[ color ];
		}
	}
}

PageDesc* PageInit( void* ptr, UINT color ) // FIXME COLOR type
{
    PageDesc* pg = new PageDesc; // new кидает исключение. А проверять мы хотим как после malloc. Так что пусть будет malloc
    if (!pg)
	return NULL;
    PAGE_INIT(*pg, ptr, color); // FIXME: но лучше inline-функцию вызвать
    return pg;
}

/**
 * Print all mapped pages
 */
void PageDump()
{
	// а вообще нехорошо так. Но если цвета 3 - можно оставить. А так - надо бы функцию GetColorName(PAGE_COLOR) сделать
	// А вообще хотя бы так, чтоб порядок не перепутать
	#define PG_COLOR_NAME(clr) #clr
	char* PgColorName[PG_COLOR_SIZE];
	PgColorName[PG_COLOR_GREEN] = PG_COLOR_NAME(PG_COLOR_GREEN),
	PgColorName[PG_COLOR_YELLOW] = PG_COLOR_NAME(PG_COLOR_YELLOW),
	PgColorName[PG_COLOR_RED] = PG_COLOR_NAME(PG_COLOR_RED),
	#undef PG_COLOR_NAME

	PAGE_COLOR color = 0; // FIXED: color type
	for( color < PG_COLOR_SIZE; color++ ) // А еще хорошо б от библиотечных вызовов избавиться
	{
		printf("PgStrg[%u (%s)] ********** \n", color, PgColorName[color] ); // FIXED: incorrect modificators order
		for( PageDesc* Pg = PageStrg[color]; Pg != NULL; Pg = Pg->next ) // FIXED: ++color??
		{
			if( Pg->uAddr == NULL ) // FIXED: ==, not =!
				continue;

			printf("Pg :Key = 0x%x, addr %x\n", Pg->uKey, Pg->uAddr ); // FIXEF: incorrect modificator
		}
	}
}
